﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using UnityEngine;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using UnityEngine.Rendering;

namespace FrameWorkSong
{
    public class WebSocketsRequest : Singleton<WebSocketsRequest>
    {
        public override void OnBeforeDestroy() { Debug.Log("exit"); SocketQuit(); }
        Dictionary<string, Mqtt> Mqtt_Dic = new Dictionary<string, Mqtt>();
        Dictionary<string, WebSockets> WebSockets_Dic = new Dictionary<string, WebSockets>();
        Dictionary<string, SocketClient> SocketClient_Dic = new Dictionary<string, SocketClient>();
        Dictionary<string, SocketServer> SocketServer_Dic = new Dictionary<string, SocketServer>();
        /// <summary>
        /// 创建Socket连接
        /// </summary>
        /// <param name="Msg">注册方法</param>
        /// <param name="URL">连接地址</param>
        public void CreateWebSockets(string Msg, string URL)
        {
            if (!WebSockets_Dic.ContainsKey(Msg))
            {
                WebSockets webSocket = new WebSockets();
                webSocket.URL = URL;
                webSocket.registerMsg = Msg;
                webSocket.ifRun = true;//Socket是否运行
                webSocket.Connect();
                if (webSocket.ifRun)
                {
                    WebSockets_Dic.Add(Msg, webSocket);
                }
            }
        }
        public void CreateMQTTnet(string Msg, string ip, int port)
        {
            if (!WebSockets_Dic.ContainsKey(Msg))
            {
                Mqtt mqtt = new Mqtt();
                mqtt.My_IP = ip;
                mqtt.My_Port = port;
                mqtt.registerMsg = Msg;
                mqtt.MyMqttClient();
                if (mqtt.ifRun)
                {
                    Mqtt_Dic.Add(Msg, mqtt);
                }

            }
        }

        /// <summary>
        /// 创建客户端连接
        /// </summary>
        /// <param name="Msg">注册方法</param>
        /// <param name="IP">ip</param>
        /// <param name="Port">端口</param>
        public void CreateSocketClient(string Msg, string IP, int Port)
        {
            if (!SocketClient_Dic.ContainsKey(Msg))
            {
                SocketClient socketClient = new SocketClient();
                socketClient.registerMsg = Msg;
                socketClient.Connect(IP, Port);
                if (socketClient.ifRun)
                {
                    SocketClient_Dic.Add(Msg, socketClient);
                }
            }
        }
        /// <summary>
        /// 创建服务器端连接
        /// </summary>
        /// <param name="Msg">注册方法</param>
        /// <param name="IP">ip</param>
        /// <param name="Port">端口</param>
        public void CreateSocketServer(string Msg, string IP, int Port)
        {
            if (!SocketServer_Dic.ContainsKey(Msg))
            {
                SocketServer socketServer = new SocketServer();
                socketServer.registerMsg = Msg;
                socketServer.CreateSocket(IP, Port);
                SocketServer_Dic.Add(Msg, socketServer);
            }
        }
        /// <summary>
        ///  创建服务器端连接
        /// </summary>
        /// <param name="Msg">注册方法</param>
        /// <param name="Port">端口</param>
        public void CreateSocketServer(string Msg, int Port)
        {
            if (!SocketServer_Dic.ContainsKey(Msg))
            {
                SocketServer socketServer = new SocketServer();
                socketServer.registerMsg = Msg;
                socketServer.CreateSocket(Port);
                SocketServer_Dic.Add(Msg, socketServer);
            }
        }
        /// <summary>
        /// 断开Socket连接
        /// </summary>
        /// <param name="Msg">注册方法</param>
        public void RemoveSockets(string Msg)
        {
            if (WebSockets_Dic.ContainsKey(Msg))
            {
                WebSockets webSocket = WebSockets_Dic[Msg];
                webSocket.ifRun = false;
                WebSockets_Dic.Remove(Msg);
            }
            if (SocketClient_Dic.ContainsKey(Msg))
            {
                SocketClient socketClient = SocketClient_Dic[Msg];
                socketClient.Remove();
                SocketClient_Dic.Remove(Msg);
            }
            if (SocketServer_Dic.ContainsKey(Msg))
            {
                SocketServer socketServer = SocketServer_Dic[Msg];
                socketServer.Remove();
                SocketServer_Dic.Remove(Msg);
            }
            if (Mqtt_Dic.ContainsKey(Msg))
            {
                Mqtt mqtt = Mqtt_Dic[Msg];
                mqtt.Disconnect();
                Mqtt_Dic.Remove(Msg);
            }
        }

        /// <summary>
        /// 客户端消息发送
        /// </summary>
        /// <param name="Msg">注册方法</param>
        /// <param name="Info">发送消息string</param>
        public void SocketClientSend(string Msg, string Info)
        {
            if (SocketClient_Dic.ContainsKey(Msg))
            {
                SocketClient socketClient = SocketClient_Dic[Msg];
                socketClient.Send(Info);
            }
        }
        /// <summary>
        /// 服务器发布消息
        /// </summary>
        /// <param name="Msg"></param>
        /// <param name="Info"></param>
        public void SocketServerSend(string Msg, string Info)
        {
            if (SocketServer_Dic.ContainsKey(Msg))
            {
                SocketServer SocketServer = SocketServer_Dic[Msg];
                SocketServer.Send(Info);
            }
        }
        /// <summary>
        /// 自动退出Socket
        /// </summary>
        void SocketQuit()
        {
            foreach (var item in WebSockets_Dic)
            {
                item.Value.ifRun = false;
            }
            foreach (var item in SocketClient_Dic)
            {
                item.Value.Remove();
            }
            foreach (var item in SocketServer_Dic)
            {
                item.Value.Remove();
            }
        }



    }

    public class Mqtt : MonoBehaviourSimplify
    {
        private IMqttClient m_MqttClient = null;
        private string m_ClientID;
        public string clientID;
        public string My_IP = "127.0.0.1";
        public int My_Port = 1883;
        public bool ifRun = true;
        public string registerMsg = "";

        //MqttClientWebSocketOptionsBuilder Builder()
        //{
        //    MqttClientWebSocketOptionsBuilder Builder1 = new MqttClientWebSocketOptionsBuilder().WithUri("ws://broker.hivemq.com:8000/mqtt");
        //    return Builder1;
        //}
        /// <summary>
        /// 创建客户端并连接服务器
        /// </summary>
        /// <param name="clientID"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void MyMqttClient()
        {
            //   m_ClientID = clientID;
            var vaule = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds().ToString();
            //  Debug.Log(vaule);
            //var socketBuilder = new MqttClientWebSocketOptionsBuilder()
            //    .WithUri("ws://broker.hivemq.com:8000/mqtt");
            //客户端选项生成器
            var options = new MqttClientOptionsBuilder()
            //.WithClientId(m_ClientID)
            // .WithTcpServer("121.40.253.229", 1883)
            .WithTcpServer(My_IP, My_Port)
            .WithCredentials("admin", "public") // 添加用户名和密码
            .WithClientId("unity3d" + vaule) // 设置客户端id
            .Build();

            //创建客户端
            m_MqttClient = new MqttFactory().CreateMqttClient();
            //监测客户端 连接/断开连接 完成
            m_MqttClient.ConnectedAsync += ClientConnected;
            m_MqttClient.DisconnectedAsync += ClientDisConnected;
            //客户端接收到消息
            m_MqttClient.ApplicationMessageReceivedAsync += ReceiveMsg;
            //连接服务器
            m_MqttClient.ConnectAsync(options);

        }

        /// <summary>
        /// 接收到消息
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        private System.Threading.Tasks.Task ReceiveMsg(MqttApplicationMessageReceivedEventArgs args)
        {
            //  Debug.Log($"Receive Message From Client:{args.ClientId} msg:{Encoding.UTF8.GetString(args.ApplicationMessage.Payload)}");
            SendMsg(registerMsg, Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment));

            return System.Threading.Tasks.Task.CompletedTask;
        }

        /// <summary>
        /// 断开连接完成
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        private System.Threading.Tasks.Task ClientDisConnected(MqttClientDisconnectedEventArgs args)
        {
            Debug.Log("disConnected");
            SendMsg(registerMsg, "连接中断");
            return System.Threading.Tasks.Task.CompletedTask;
        }

        /// <summary>
        /// 连接完成
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        private System.Threading.Tasks.Task ClientConnected(MqttClientConnectedEventArgs args)
        {
            Debug.Log("connected");

            Subscribe("unity3d");

            return System.Threading.Tasks.Task.CompletedTask;
        }

        /// <summary>
        /// 发布消息
        /// </summary>
        public void PublishMsg(string topic, string message, MqttQualityOfServiceLevel level = MqttQualityOfServiceLevel.ExactlyOnce, bool isRetain = false)
        {
            m_MqttClient.PublishStringAsync(topic, message, level, isRetain);
        }

        /// <summary>
        /// 订阅主题
        /// </summary>
        public void Subscribe(string topic)
        {
            m_MqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());

        }
        public void Disconnect()
        {
            m_MqttClient.DisconnectAsync(new MqttClientDisconnectOptionsBuilder().WithReason(MqttClientDisconnectOptionsReason.NormalDisconnection).Build());
            // Debug.Log("dis");
        }

        public override void OnBeforeDestroy()
        {
            Disconnect();
        }
    }

    public class WebSockets : MonoBehaviourSimplify
    {
        readonly ClientWebSocket _webSocket = new ClientWebSocket();
        readonly CancellationToken _cancellation = new CancellationToken();
        public string URL = "";
        public bool ifRun = true;
        public string registerMsg = "";

        public override void OnBeforeDestroy() { ifRun = false; }

        public async void Connect()
        {
            Debug.Log("hello,_webSocket001");
            try
            {
                Debug.Log("开始监听");
                //添加header
                _webSocket.Options.SetRequestHeader("admin", "public");
                // _webSocket.Options.Credentials = 
                //建立连接
                Debug.Log(URL);
                await _webSocket.ConnectAsync(new Uri(URL), _cancellation);
                Debug.Log("1");
                var bsend = Encoding.UTF8.GetBytes("holle");
                Debug.Log("hello,_webSocket：" + URL);
                await _webSocket.SendAsync(new ArraySegment<byte>(bsend), WebSocketMessageType.Binary, true, _cancellation); //发送数据
                while (ifRun)
                {
                    var result = new byte[1024];
                    await _webSocket.ReceiveAsync(new ArraySegment<byte>(result), new CancellationToken());//接受数据
                    Debug.Log(result.Length);
                    var str = UTF8Encoding.UTF8.GetString(result, 0, result.Length);
                    string[] data = str.Split('%');//%代表json字符串结束
                    Debug.Log("Start" + data[0] + "End");
                    Debug.Log(data.Length);
                    SendMsg(registerMsg, str);
                }
            }
            catch
            {
                ifRun = false;
                SendMsg(registerMsg, "失败");
            }
        }




    }

    public class SocketClient : MonoBehaviourSimplify
    {
        Socket socket;
        Thread c_thread;
        public bool ifRun;
        public string registerMsg;
        public void Connect(string IP, int Port)
        {
            try
            {
                //创建客户端Socket，获得远程ip和端口号
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Parse(IP);
                IPEndPoint point = new IPEndPoint(ip, Port);
                IAsyncResult result = socket.BeginConnect(point, new AsyncCallback(sendCallBack), socket);
                bool success = result.AsyncWaitHandle.WaitOne(5000, true);
                if (success)
                {
                    Debug.Log("连接成功!");
                }
                else
                {
                    Debug.Log("连接失败!");
                }
                //socketSend.Connect(point);

                //开启新的线程，不停的接收服务器发来的消息
                c_thread = new Thread(Received);
                c_thread.IsBackground = true;
                c_thread.Start();
            }
            catch (Exception)
            {
                Debug.Log("IP或者端口号错误...");
            }
        }
        private void sendCallBack(IAsyncResult ar)
        {
            Debug.Log(ar.IsCompleted);
            ifRun = ar.IsCompleted;
        }

        /// <summary>
        ///断开
        ///</summary>
        public void Remove()
        {
            if (!ifRun)
                return;
            ifRun = false;
            if (c_thread != null)
                c_thread.Abort();
            c_thread = null;
            if (socket != null && socket.Connected)
                socket.Close();
            socket = null;
        }
        /// <summary>
        /// 接收服务端返回的消息
        /// </summary>
        void Received()
        {
            while (true)
            {
                if (!socket.Connected)
                {
                    ifRun = false;
                    break;
                }
                try
                {
                    byte[] buffer = new byte[1024 * 1024 * 3];
                    //实际接收到的有效字节数
                    int len = socket.Receive(buffer);
                    if (len == 0)
                    {
                        break;
                    }
                    string str = Encoding.UTF8.GetString(buffer, 0, len);
                    Debug.Log("客户端打印：" + socket.RemoteEndPoint + ":" + str);
                    SendMsg(registerMsg, str);
                }
                catch { }
            }
        }
        /// <summary>
        /// 向服务器发送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Send(string str)
        {
            try
            {
                string msg = str;
                byte[] buffer = new byte[1024 * 1024 * 3];
                buffer = Encoding.UTF8.GetBytes(msg);
                socket.Send(buffer);
            }
            catch { }
        }

        public override void OnBeforeDestroy()
        {
            Remove();
        }
    }

    public class SocketServer : MonoBehaviourSimplify
    {
        Socket socketWatch;
        Thread thread;
        public string registerMsg;
        string getIP()
        {
            string ip4 = "";
            IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());   //Dns.GetHostName()获取本机名Dns.GetHostAddresses()根据本机名获取ip地址组
            foreach (IPAddress ip in ips)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    ip4 = ip.ToString();  //ipv4

                }
                //else if (ip.AddressFamily == AddressFamily.InterNetworkV6)
                //{
                //    ipv6 = ip.ToString(); //ipv6
                //}
            }
            return ip4;
        }
        public void CreateSocket(int Port)
        {
            string IP = getIP();//"127.0.0.1";
            Connect(IP, Port);
        }

        public void CreateSocket(string IP, int Port)
        {
            Connect(IP, Port);
        }
        private void Connect(string IP, int Port)
        {
            try
            {
                //点击开始监听时 在服务端创建一个负责监听IP和端口号的Socket
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Parse(IP);
                //创建对象端口
                IPEndPoint point = new IPEndPoint(ip, Port);

                socketWatch.Bind(point);//绑定端口号
                Debug.Log("监听成功!");
                socketWatch.Listen(10);//设置监听，最大同时连接10台

                //创建监听线程
                thread = new Thread(Listen);
                thread.IsBackground = true;
                thread.Start(socketWatch);
            }
            catch { }
        }
        /// <summary>
        /// 等待客户端的连接 并且创建与之通信的Socket
        /// </summary>
        Socket socketSend;
        void Listen(object o)
        {
            try
            {
                Socket socketWatch = o as Socket;
                while (true)
                {
                    socketSend = socketWatch.Accept();//等待接收客户端连接
                    Debug.Log(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功!");
                    //开启一个新线程，执行接收消息方法
                    Thread r_thread = new Thread(Received);
                    r_thread.IsBackground = true;
                    r_thread.Start(socketSend);
                }
            }
            catch { }
        }
        /// <summary>
        /// 服务器端不停的接收客户端发来的消息
        /// </summary>
        /// <param name="o"></param>
        void Received(object o)
        {
            try
            {
                Socket socketSend = o as Socket;
                while (true)
                {
                    //客户端连接服务器成功后，服务器接收客户端发送的消息
                    byte[] buffer = new byte[1024 * 1024 * 3];
                    //实际接收到的有效字节数
                    int len = socketSend.Receive(buffer);
                    if (len == 0)
                    {
                        break;
                    }
                    string str = Encoding.UTF8.GetString(buffer, 0, len);
                    Debug.Log("服务器打印：" + socketSend.RemoteEndPoint + ":" + str);
                    SendMsg(registerMsg, str);
                    Send("我收到了");
                }
            }
            catch { }
        }
        public void Send(string str)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(str);
            socketSend.Send(buffer);
        }
        public void Remove()
        {
            //先关闭客户端
            if (socketSend != null)
                socketSend.Close();
            //再关闭线程
            if (thread != null)
            {
                thread.Interrupt();
                thread.Abort();
            }
            //最后关闭服务器
            socketWatch.Close();

        }

        public override void OnBeforeDestroy()
        {


        }
    }
}
